/**
 * Copyright (c) 2014-2016 www.nryuncang.com. All Rights Reserved.
 */
package com.topisv.tms.service.print.impl;

import static com.google.common.base.Preconditions.checkArgument;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.EdiOrder;
import com.topisv.tms.entity.EdiOrderItem;
import com.topisv.tms.entity.ExpressConfigure;
import com.topisv.tms.entity.ExpressStyle;
import com.topisv.tms.entity.WarehouseAddress;
import com.topisv.tms.entity.work.WorkOrder;
import com.topisv.tms.entity.work.WorkTask;
import com.topisv.tms.mybatis.SqlMapDao;
import com.topisv.tms.repository.EdiOrderDao;
import com.topisv.tms.service.ExpressConfigureService;
import com.topisv.tms.service.WarehouseAddressService;
import com.topisv.tms.service.work.WorkOrderService;
import com.topisv.tms.service.work.WorkTaskService;
import com.topisv.tms.utils.ExpressUtil;

/**
 * 顺丰打印
 *
 * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
 * @version 0.0.16
 */
@Component
public class SFPrintServiceImpl extends AbstractPrintService {
	
	private static final Logger logger = LoggerFactory.getLogger(SFPrintServiceImpl.class);

	private static final String SF_ORDER_SERVICE = "OrderService";
	private static final String SF_PAY_METHOD = "1";
	private static final String PARECEL_QUANTITY = "1";
	private static final String IS_GEN_BILL_NO = "1";

	@Autowired
	private WorkTaskService workTaskService;
	@Autowired
	private ExpressConfigureService expressConfigureService;
	@Autowired
	private WarehouseAddressService warehouseAddressService;
	@Autowired
	private SqlMapDao sqlMapDao;
	@Autowired
	private WorkOrderService workOrderService;
	@Autowired
	private EdiOrderDao ediOrderDao;

	@SuppressWarnings("unchecked")
    @Override
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public List<EdiOrder> doGetExpressNo(List<String> orderNoList, ExpressStyle template, String taskCode) throws Exception {

		// 第一步:得到基础信息如作业任务，订单列表、仓库信息、配置信息
		WorkTask workTask = workTaskService.loadTaskByCode(taskCode);
		ExpressConfigure expressConfigure = expressConfigureService.findByWarehouseAndCompany(workTask.getWarehouseCode(), template.getLogisticsCompany().getCompanyCode());
		
		WarehouseAddress warehouseAddress = warehouseAddressService.findByWarehouseCode(workTask.getWarehouseCode());
		
		List<EdiOrder> ediOrderList = sqlMapDao.selectList("ediOrderMapper.getEdiOrderListByOrdeno", orderNoList);

		// 第二步:循环订单
		for (EdiOrder ediOrder : ediOrderList) {
			
			// 查询订单明细中的商品信息
			List<EdiOrderItem> ediOrderItemList = sqlMapDao.selectList("ediOrderItemMapper.getSkuInfoByOrdeno", ediOrder);
			
			WorkOrder workOrder = workOrderService.loadOrder(ediOrder.getBatchTaskCode(), ediOrder.getOrdeno());
			
			if (workOrder.getEbillNo() == null || "cbill".equals(workOrder.getBillType())
					|| !template.getLogisticsCompany().getCompanyCode().equals(workOrder.getExpressCompany())) {

				// 拼装报文
				String content = getSFXml(ediOrder, ediOrderItemList, expressConfigure, warehouseAddress,template);
				logger.info("{}=顺丰取单号报文={}", ediOrder.getOrdeno(), content);
				
				// 发送顺丰接口,接收返回值
				String returnData = returnSFResult(content, expressConfigure);
				logger.info("{}=顺丰取单号返回的报文={}", ediOrder.getOrdeno(), returnData);
				
				// 解析返回值处理，赋值
				Map<String, Object> result = parseSFResultXML(returnData);
				String headText = String.valueOf(result.get("headText"));
				if ("ERR".equals(headText)) {
					logger.error("{}=获取顺丰面单号失败={}"+ediOrder.getOrdeno(), result);
					 throw new RuntimeException (ediOrder.getOrdeno() + "=获取顺丰面单号失败=" + result.get("code") + "--" + result.get("errorText"));
				} else {
					if (result.get("mailno") == null || "".equals(result.get("mailno"))) {
						logger.error("{}=获取顺丰面单号为空={}"+ediOrder.getOrdeno(),result);
						 throw new RuntimeException(ediOrder.getOrdeno() + "=顺丰电子面单号为空=");
					} else if ("3".equals(result.get("filter_result"))) {
						logger.error("{}=顺丰不能收派={}"+ediOrder.getOrdeno(),result);
					    throw new RuntimeException(ediOrder.getOrdeno() + "=顺丰超区，不派送=");
					}

					workOrder.setExpressName(template.getBarCode());
					ediOrder.setCacode(template.getLogisticsCompany().getCompanyCode());//快递公司代码
					ediOrder.setCaname(template.getLogisticsCompany().getCompanyName());//快递公司名称
					ediOrder.setMailNo(String.valueOf(result.get("mailno")));//运单号
					ediOrder.setDestCode(String.valueOf(result.get("destcode")));//目的地编码
					ediOrder.setOriginCode(String.valueOf(result.get("origincode")));//原寄地编码
					ediOrder.setFilterResult(String.valueOf(result.get("filter_result")));//筛单结果:1(人工确认)，2(可派收),3(不可派收)
				}
			}

		}
		ediOrderDao.save(ediOrderList);
		
		return ediOrderList;
	}

	/**
	 * 
	 * 发送顺丰接口 post，返回请求结果
	 *
	 * @param xml
	 *            报文
	 * @param expressConfigure
	 *            配置信息
	 * @return
	 * @throws Exception
	 *             [参数说明]
	 * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
	 * @version 0.0.16
	 */
	private String returnSFResult(String xml, ExpressConfigure expressConfigure) throws Exception {

		String appKey = expressConfigure.getAppKey();
		String url = expressConfigure.getUrl();

		// 校验账号、密码
		checkArgument(StringUtils.isNotEmpty(appKey), String.format("appKey is empty"));
		checkArgument(StringUtils.isNotEmpty(url), String.format("url is empty"));

		String verifyCode = ExpressUtil.encryptBASE64(ExpressUtil.digestMD5(xml + appKey));

		List<NameValuePair> parameters = new ArrayList<NameValuePair>();
		parameters.add(new BasicNameValuePair("xml", xml));
		parameters.add(new BasicNameValuePair("verifyCode", verifyCode));
		
		return super.requestExpressNo(url, parameters);
	}
	
	/**
	 * 
	 * 顺丰取运单号请求报文
	 *
	 * @param order
	 *            订单
	 * @param ediOrderItemList
	 *            订单明细
	 * @param expressConfigure
	 *            配置信息
	 * @param warehouseAddress
	 *            仓库地址
	 * @param express_type
	 *            顺丰业务类型
	 * @return [参数说明]
	 * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
	 * @version 0.0.16
	 */
	private String getSFXml(EdiOrder order, List<EdiOrderItem> ediOrderItemList, ExpressConfigure expressConfigure,
			WarehouseAddress warehouseAddress, ExpressStyle expressType) {

		Document document = DocumentHelper.createDocument();

		// 定义root节点
		Element rootElement = document.addElement("Request");
		rootElement.addAttribute("service", SF_ORDER_SERVICE);
		rootElement.addAttribute("lang", "zh-CN");

		// 定义head节点
		Element headElement = rootElement.addElement("Head");
		headElement.setText(expressConfigure.getMonthAccount());

		// 定义body节点内容
		Element bodyElement = rootElement.addElement("Body");
		Element orderElement = bodyElement.addElement("Order");   
		// 订单号
		orderElement.addAttribute("orderid", order.getOrdeno());
		// 产品类型
		orderElement.addAttribute("express_type", expressType.getBarCode());
		// 付款方式 1、寄方付 2、收方付 3、第三方付
		orderElement.addAttribute("pay_method", SF_PAY_METHOD);
		// 寄方公司
		orderElement.addAttribute("j_company", warehouseAddress.getCompany());
		// 寄方联系人
		orderElement.addAttribute("j_contact", warehouseAddress.getContact());
		// 寄方电话
		orderElement.addAttribute("j_tel", warehouseAddress.getMobile());
		// 寄方省份
		orderElement.addAttribute("j_province", warehouseAddress.getProvName());
		// 寄方城市
		orderElement.addAttribute("j_city", warehouseAddress.getCityName());
		// 寄方地址
		orderElement.addAttribute("j_address", warehouseAddress.getAddress());
		// 收方联系人
		orderElement.addAttribute("d_contact", order.getRecena());
		// 收方联系电话
		orderElement.addAttribute("d_tel",StringUtils.isBlank(order.getMobile()) ? order.getTeleph() : order.getMobile());
		// 收方省份
		orderElement.addAttribute("d_province", order.getProvna());
		// 收方城市
		orderElement.addAttribute("d_city", order.getCityna());
		// 收方地址
		orderElement.addAttribute("d_address", order.getAddres());
		// 顺丰月结账号
		orderElement.addAttribute("custid", warehouseAddress.getSfmonth());
		// 包裹数
		orderElement.addAttribute("parcel_quantity", PARECEL_QUANTITY);
		// 是否申请运单号
		orderElement.addAttribute("is_gen_bill_no", IS_GEN_BILL_NO);

		for (EdiOrderItem item : ediOrderItemList) {
			Element cargoElement = orderElement.addElement("Cargo");
			cargoElement.addAttribute("name", item.getNam());
			cargoElement.addAttribute("count", String.valueOf(item.getQty()));
			cargoElement.addAttribute("unit", item.getUnit());
			cargoElement.addAttribute("weight", item.getWeight());
			cargoElement.addAttribute("amount", String.valueOf(item.getPri()));
			cargoElement.addAttribute("currency", item.getCurrency());
			cargoElement.addAttribute("source_area", item.getOriginCountry());
		}

		//保价不固定  add by zhangweize bug613顺丰快递增加保价
        if (expressType.getIsInsured().intValue() == 1) {
            if (StringUtils.isNotBlank(order.getTotalAmount().toString())) {
                logger.info("顺丰保价不固定={}=", order.getOrdeno());
                Element addedServiceElement = orderElement.addElement("AddedService");
                addedServiceElement.addAttribute("name", "INSURE");
                addedServiceElement.addAttribute("value", order.getTotalAmount().toString());//声明价值
                order.setInsuranceAmt(order.getTotalAmount().doubleValue() * expressType.getInsuredPoint().doubleValue());
            } else {
                throw new RuntimeException(order.getOrdeno() + "=顺丰保价不固定，但商品总金额(total_amount)为空");
            }
        } else if(expressType.getIsInsured().intValue() == 2){//保价固定 add by zhangweize bug613顺丰快递增加保价 
            logger.info("顺丰保价固定={}=", order.getOrdeno());
            Element addedServiceElement = orderElement.addElement("AddedService");
            addedServiceElement.addAttribute("name", "INSURE");
            addedServiceElement.addAttribute("value", expressType.getInsuredPoint().toString());//声明价值
        } else {
            logger.info("顺丰不保价={}=", order.getOrdeno());
        }
		return document.asXML();
	}
   
	/**
	 * 解析顺丰请求的报文
	 * 
	 *
	 * @param xml 返回的报文
	 * @return
	 * @throws Exception [参数说明]
	 * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
	 */
	public Map<String, Object> parseSFResultXML(String xml) throws Exception {

		Map<String, Object> result = new HashMap<String, Object>();
		Document document = DocumentHelper.parseText(xml);
		Element rootElement = document.getRootElement();

		String serviceName = rootElement.attributeValue("service");
		result.put("serviceName", serviceName);
		Element headElement = rootElement.element("Head");
		String headText = headElement.getText();
		result.put("headText", headText);
		if ("OK".equals(headText)) {
			Element bodyElement = rootElement.element("Body");
			Element responseElement = bodyElement.element("OrderResponse");
			result.put("filter_result", responseElement.attributeValue("filter_result"));//筛单接口(1、人工确认 2、可收派  3、不可以收派)
			result.put("destcode", responseElement.attributeValue("destcode"));//目的地编码
			result.put("mailno", responseElement.attributeValue("mailno"));//运单号
			result.put("origincode", responseElement.attributeValue("origincode"));//原寄地编码;
			result.put("orderid", responseElement.attributeValue("orderid"));//订单号
		} else {
			Element errorElement = rootElement.element("ERROR");
			String code = errorElement.attributeValue("code");
			result.put("code", code);
			result.put("errorText", errorElement.getText());
		}
		return result;
	}
}
